/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package testkryo.impl;

import java.io.IOException;

import com.esotericsoftware.kryo.Kryo;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import testkryo.BufferUtil;

/**
 *
 * @author camomot
 */
public class KryoAppendStorer {

  private Path storageFile;
  private Path storagePath = Paths.get("src/data");
  private Kryo kryo = new Kryo();

  public Kryo getKryo() {
    return kryo;
  }

  public KryoAppendStorer(String storageFileStr) {
    storageFile = storagePath.resolve(storageFileStr);
    try {
      Files.createFile(storageFile);
    } catch (FileAlreadyExistsException fx) {
    } catch (IOException ex) {
      Logger.getLogger(KryoStorer.class.getName()).log(Level.SEVERE, null, ex);
    }
  }

  public Pointer store(Object o) {
    if (o == null) {
      return null;
    }
    Pointer temp = null;
    ByteBuffer buffer = ByteBuffer.allocate(256);
    FileChannel fc = null;
    kryo.writeObject(buffer, o);
    buffer.flip();
    try {
      fc = FileChannel.open(storageFile, StandardOpenOption.READ, StandardOpenOption.WRITE);
      long pos = fc.size() == 0 ? 0 : fc.size();
      fc.position(pos);
      fc.write(buffer);

      temp = new Pointer(pos, (long) buffer.limit());
    } catch (IOException ex) {
      Logger.getLogger(KryoStorer.class.getName()).log(Level.SEVERE, null, ex);
    } finally {
      if (fc != null) {
        try {
          fc.close();
        } catch (IOException ex) {
          Logger.getLogger(KryoStorer.class.getName()).log(Level.SEVERE, null, ex);
        }
      }
    }
    return temp;
  }

  public <T> T get(Pointer p, Class<T> c) {
    T o = null;
    FileChannel fc = null;

    if (p != null) {
      long pos = p.pos;
      long len = p.len;

      try {
        fc = FileChannel.open(storageFile, StandardOpenOption.READ, StandardOpenOption.WRITE);

        fc.position(pos);

        ByteBuffer buffer = ByteBuffer.allocate((int) len);

        fc.read(buffer);
        buffer.flip();
        o = (T) kryo.readObject(buffer, c);

      } catch (IOException ex) {
        Logger.getLogger(KryoAppendStorer.class.getName()).log(Level.SEVERE, null, ex);
      } finally {
        if (fc != null) {
          try {
            fc.close();
          } catch (IOException ex) {
            Logger.getLogger(KryoAppendStorer.class.getName()).log(Level.SEVERE, null, ex);
          }
        }
      }
    }
    return o;
  }
}
